//
//  PageCache.cpp
//  高并发内存池
//
//  Created by 卜绎皓 on 2023/2/14.
//

#include "PageCache.hpp"

//获取一个k页的span
Span* PageCache::NewSpan(size_t k)
{
    assert(k > 0 && k < NPAGES);
    //先检查第k个桶里面有没有span
    if (!_spanLists[k].Empty())
    {
        return _spanLists[k].PopFront();
    }
    //检查一下后面的桶里面有没有span，如果有可以将其进行切分
    for (size_t i = k + 1; i < NPAGES; i++)
    {
        if (!_spanLists[i].Empty())
        {
            Span* nSpan = _spanLists[i].PopFront();
            Span* kSpan = new Span;
            //在nSpan的头部切k页下来
            kSpan->_pageId = nSpan->_pageId;
            kSpan->_n = k;

            nSpan->_pageId += k;
            nSpan->_n -= k;
            //将剩下的挂到对应映射的位置
            _spanLists[nSpan->_n].PushFront(nSpan);
            return kSpan;
        }
    }
    //走到这里说明后面没有大页的span了，这时就向堆申请一个128页的span
    Span* bigSpan = new Span;
    void* ptr = SystemAlloc(NPAGES - 1);
    bigSpan->_pageId = (PAGE_ID)ptr >> PAGE_SHIFT;
    bigSpan->_n = NPAGES - 1;

    _spanLists[bigSpan->_n].PushFront(bigSpan);

    //尽量避免代码重复，递归调用自己
    return NewSpan(k);
}
